'''
	The PlayBackControlller allows recordings to be played back. 
	
	@author: J.H.Donker
	@copyright: Twente University
'''
import wx
from InputController import InputController
from InputInterface import InputWrapper
from model import *
from wx.lib.pubsub import Publisher


class PlayBackController(InputController):
	'''
		The playback controller plays back recordings. Recordings can be played
		back and be stepped trough. It uses the wrapping.
	'''
	BACKWARDS = -1
	STOP = 0	
	FORWARD = 1
	
	MILI = 1000
	MINI_STEP = 30

	
	def __init__(self, inputInterface, recording):
		'''
			Constructor. A PlayBackController is always mapped to a single recording. 
			
			@param inputInterface: The wrapper for the model.
			@param recording: The recording that will be played back.
		'''
		InputController.__init__(self, inputInterface)
		self.__recording = recording
		self.__direction = 0
		self.__position = 0
		self.__timer = wx.Timer(None, -1)
		self.__timer.Bind(wx.EVT_TIMER, self._onTick)

	def _onTick(self, event):
		'''
			Tick mehod for the playback timer.
		'''
		self.Consume(False)
			
	def Start(self):
		'''
			Starts playing forward. 
		'''
		self.Direction(PlayBackController.FORWARD)
		self.Consume(False)
	
	def Step(self):
		'''
			Move the recording one atom forward. 
		'''
		self.Consume(True)
	
	def Direction(self, value):
		'''
			Sets the direction of playback.
			
			@param value: The direction can FORWARD, PAUSE and BACKWARD
		'''
		self.__direction = value
		
	def SetPosition(self, index):
		'''
			Sets the current placyback position.
			
			@param index: The index of the current position.
		'''
		atoms =  self.__recording.GetNumberOfAtoms()
		if index in range(0,atoms ):
			self.__position = index
	
	def GetDirection(self):
		'''
			Returns the current playback direction.
			
			@return: Can be FORWARD, PAUSE and BACKWARD
		'''
		return self.__direction
		
	def GetPosition(self):
		'''
			Returns the current playback position
			
			@return: Index of the current atom.
		'''
		return self.__position
		
	def GetMax(self):
		'''
			Returns the number of atoms in the recording.
			
			@return: Number of atoms in recording.
		'''
		return self.__recording.GetNumberOfAtoms()
			
	def Consume(self, OneShot):
		'''
			Consumes a atom, and if it's not a oneshot will go the next, atom.
			A oneshote call to this wil mean you only consume the current atom.
			
			@param OneShot: When true, will go to the next atom afterwards.  
							When false will stop after consuming atom. 
		'''
		
		#playing back needs at least two atoms to make sense 
		if self.__recording.GetNumberOfAtoms() > 1:
		
			#rename the inputwrapper for convience
			interface = self._inputInterface
			#rename the current atom for convience
			atom = self.__recording.GetAtom(self.__position)
			
			#fetch data from atom.
			type = atom.GetType()
			x,y,z = atom.GetValue()
			
			
			#execute the current data fragment
			if type == RecordingAtom.ORIENTATION:
				interface.SetOrientationInstrument(x,y,z)
			elif type == RecordingAtom.POSITION:
				interface.SetPositionInstrument(x,y,z)
			elif type == RecordingAtom.SCALE:
				interface.SetScaleInstrument(x,y,z)
			
			#alert the gui that we moved
			status = float(self.__position) / float(self.__recording.GetNumberOfAtoms()-1)
			Publisher.sendMessage("PlayBackUpdate", status)
			
			
			if not OneShot:
				#we ar are playing so go to the next one. 
				self.Next()

	def Next(self):
		'''
			Goes to the next atom depending on direction and position. 
		'''
		nextpointer = 0
		#fetch the current atom for reference purpose
		atom = self.__recording.GetAtom(self.__position)

		#determine the desired direction
		if self.__direction ==  PlayBackController.BACKWARDS:
			nextpointer = -1
		elif self.__direction == PlayBackController.STOP:
			nextpointer = 0
		elif self.__direction == PlayBackController.FORWARD:
			nextpointer = 1
		
		#calculate the next position
		next = self.__position + nextpointer
		
		#check if the next pointer is in range or that we have stopped. 
		if next in range(0,self.__recording.GetNumberOfAtoms()) and self.__direction != 0:
			
			#fetch the next atom
			self.__position = next
			nextAtom = self.__recording.GetAtom(self.__position)

			#calculate the time delta between two atoms. 
			milis = int(abs(atom.GetTimeStamp() - nextAtom.GetTimeStamp()) * PlayBackController.MILI)

			#if the timestep is nothing, insert a small numner.
			if milis == 0:
				milis = PlayBackController.MINI_STEP
			
			#wait once for a specified numbr of miliseconds. 
			self.__timer.Start(milis, True)
		else:
			#nothing to do, so we just stop. 
			self.__direction = PlayBackController.STOP
	
	def Stop(self):
		'''
			Stops the playback
		'''
		self.__direction = PlayBackController.STOP
		self.__timer.Stop()